/**
 * Copyright 2005 SIB Framework

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */



/**
 * this class compress files to a zip file
 */
package org.sibframework.utils;


import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;

//TODO tobe merger into zip
public class JarTool {

	/**
	 * the buffer size when write data.
	 */
	private static final int BUFFER = 4096;

	/**
	 * a buffer for dual data
	 */
	private byte[] data = new byte[BUFFER];

	/**
	 * input stream
	 */
	private BufferedInputStream origin = null;

	/**
	 * @param srcs source file names to compress, String arrary.
	 * @param target target jar file name.
	 * @return ture/false.
	 */

	public final boolean compress(final String[] srcs, final String target) {
		File[] files = new File[srcs.length];
		for (int j = 0; j < srcs.length; j++) {
			File f = new File(srcs[j]);
			files[j] = f;
		}
		return this.compress(files, new File(target));
	}
	public final boolean compress(final File[] srcs, final File target) {
		try {
			FileOutputStream dest = new FileOutputStream(target);
			JarOutputStream out = new JarOutputStream(new BufferedOutputStream(
					dest));
			// out.setMethod(JarOutputStream.DEFLATED);
			// get a list of files from current directory
			for (int j = 0; j < srcs.length; j++) {
				File f = srcs[j];
				if (!f.isDirectory()) {
					invokeFile(f, out, "");
				} else {
					invokeDir(f, out, "");
				}
			}

			out.close();
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	public void addFiles(InputStream sjarFileis, File tjarFile, File[] files) {
		if (sjarFileis == null) {
			return;
		}
		try {
			
			//make the temp jar file
			File tmpjarfile = File.createTempFile("jartmp", "jar");
			InputStream fis = new BufferedInputStream(sjarFileis);
			OutputStream dest = new BufferedOutputStream(new FileOutputStream(tmpjarfile));
			JarInputStream zis = new JarInputStream(fis);
			JarOutputStream out = new JarOutputStream(dest);
			for (ZipEntry entry = zis.getNextEntry();entry != null;entry = zis.getNextEntry()) {
				out.putNextEntry(entry);
				int count;
				while ((count = zis.read(data, 0, BUFFER)) != -1) {
					out.write(data, 0, count);
				}
			}
			zis.close();

			//add files to temp jar file.
			for (int i = 0; i < files.length; i++) {
				File f = files[i];
				if (!f.isDirectory()) {
					invokeFile(f, out, "");
				} else {
					invokeDir(f, out, "");
				}
			}
			out.close();
			
			//check target file.
			if (tjarFile.exists()) {
				tjarFile.delete();
			}

			//copy temp to target
	        //int bytesum = 0;
			int byteread = 0;
			File oldfile = tmpjarfile;
			if (oldfile.exists()) {
				InputStream inStream = new BufferedInputStream(new FileInputStream(oldfile));
				OutputStream fs = new BufferedOutputStream(new FileOutputStream(tjarFile));
				byte[] buffer = new byte[4096];
				while ((byteread = inStream.read(buffer)) != -1) {
					//bytesum += byteread;
					//System.out.println(bytesum);
					fs.write(buffer, 0, byteread);
				}
				inStream.close();
				fs.flush();
				fs.close();
			}  

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void extract(File jarFile, File project) {
		if (!jarFile.exists() || !jarFile.isFile()) {
			return;
		}
		try {
			FileInputStream fis = new FileInputStream(jarFile);
			extract(fis, project);
			fis.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public void extract(InputStream jarFile, File dir) {
		if (!dir.isDirectory()) {
			return;
		}
		JarInputStream zis;
		try {
			zis = new JarInputStream(jarFile);
			for (ZipEntry entry = zis.getNextEntry();entry != null;entry = zis.getNextEntry()) {
				//System.out.println(entry.getName());
				if (entry.isDirectory()) {
					File file = new File(dir.getAbsolutePath() + "\\" +  entry.getName());
					file.mkdir();
				} else {
					File file = new File(dir.getAbsolutePath() + "\\" + entry.getName());
					if (!file.getParentFile().exists()) {
						file.getParentFile().mkdir();
					}
					BufferedOutputStream dest = new BufferedOutputStream(new FileOutputStream(file));
					int count;
					while ((count = zis.read(data, 0, BUFFER)) != -1) {
						dest.write(data, 0, count);
					}
					dest.close();
				}
			}
			zis.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public InputStream readFile(File srcJar, String filename) throws IOException {
		JarInputStream zis = new JarInputStream(new FileInputStream(srcJar));
		ZipEntry entry = zis.getNextEntry();
		while (entry != null && (entry.isDirectory() || !entry.getName().equalsIgnoreCase(filename))) {
			entry = zis.getNextEntry();
		}
		if (entry == null) {
			return null;
		}
		return zis;
	}
	
	
	
	
	/**
	 * @param file directory file to compress.
	 * @param out outputstream to target jar file.
	 * @param parent parent path.
	 * @throws IOException io exceprion
	 */
	private void invokeDir(final File file, final JarOutputStream out,
			final String parent) throws IOException {

		String entryPath = parent + file.getName() + "/";
		//System.out.println("Adding dir: " + file.getName());
		ZipEntry entry = new ZipEntry(entryPath);
		out.putNextEntry(entry);

		File[] files = file.listFiles();

		for (int i = 0; i < files.length; i++) {
			if (!files[i].isDirectory()) {
				invokeFile(files[i], out, entryPath);
			} else {
				invokeDir(files[i], out, entryPath);
			}
		}

	}

	/**
	 * @param file file to compress.
	 * @param out outputstream to target jar file.
	 * @param parent parent path.
	 * @throws IOException io exceprion
	 */
	private void invokeFile(final File file, final JarOutputStream out,
			final String parent) throws IOException {
		//System.out.println("Adding file: " + file);
		FileInputStream fi = new FileInputStream(file);
		origin = new BufferedInputStream(fi, BUFFER);
		ZipEntry entry = new ZipEntry(parent + file.getName());
		out.putNextEntry(entry);
		int count;
		while ((count = origin.read(data, 0, BUFFER)) != -1) {
			out.write(data, 0, count);
		}
		origin.close();

	}

}
